package org.yan.kangaroo.auth.config.security.filter;

import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.http.HttpStatus;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.AuthenticationException;
import org.springframework.security.web.authentication.AbstractAuthenticationProcessingFilter;
import org.springframework.security.web.util.matcher.AntPathRequestMatcher;
import org.yan.kangaroo.auth.config.security.token.EmailVerifyCodeAuthenticationToken;
import org.yan.kangaroo.auth.constant.response.ResponseCodeEnum;
import org.yan.kangaroo.common.response.ResponseUtils;
import org.yan.kangaroo.common.response.Result;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

/**
 * @author wangx
 * @date 11/13/2019 10:20
 */
@Slf4j
public class EmailVerifyCodeAuthenticationFilter extends AbstractAuthenticationProcessingFilter {
    private static final String SPRING_SECURITY_FORM_EMAIL_KEY = "email";
    private static final String SPRING_SECURITY_FORM_VERIFY_CODE_ID_KEY = "captchaId";
    private static final String SPRING_SECURITY_FORM_VERIFY_CODE_VALUE_KEY = "verifyCode";

    private final String emailParameter;
    private final String verifyCodeIdParameter;

    private final StringRedisTemplate redisTemplate;

    public EmailVerifyCodeAuthenticationFilter(StringRedisTemplate redisTemplate) {
        super(new AntPathRequestMatcher("/login/email", "POST"));
        this.redisTemplate = redisTemplate;
        emailParameter = SPRING_SECURITY_FORM_EMAIL_KEY;
        verifyCodeIdParameter = SPRING_SECURITY_FORM_VERIFY_CODE_ID_KEY;
    }

    @Override
    public Authentication attemptAuthentication(HttpServletRequest request, HttpServletResponse response) throws AuthenticationException {
        String email = request.getParameter(emailParameter);
        String captchaId = request.getParameter(verifyCodeIdParameter);
        String verifyCode = request.getParameter(SPRING_SECURITY_FORM_VERIFY_CODE_VALUE_KEY);
        if (StringUtils.isBlank(email) || StringUtils.isBlank(captchaId) || StringUtils.isBlank(verifyCode)) {
            response.setStatus(HttpStatus.UNAUTHORIZED.value());
            ResponseUtils.outAsJson(response, Result.error(ResponseCodeEnum.EMAIL_OR_VERIFY_CODE_ID_PARAMS_DEFECT));
            return null;
        }
        String redisCode = redisTemplate.opsForValue().get(captchaId);
        if (StringUtils.isBlank(redisCode)) {
            ResponseUtils.outAsJson(response, Result.error(ResponseCodeEnum.VERIFY_CODE_INVALID));
            return null;
        }

        if (!redisCode.toLowerCase().equals(verifyCode.toLowerCase())) {
            log.info("验证码错误：code:" + verifyCode + "，redisCode:" + redisCode);
            ResponseUtils.outAsJson(response, Result.error(ResponseCodeEnum.VERIFY_CODE_INPUT_ERROR));
            return null;
        }
        // 已验证清除key
        redisTemplate.delete(captchaId);
        log.info("[attemptAuthentication] email:{},verifyCode:{}", email, verifyCode);
        EmailVerifyCodeAuthenticationToken authenticationToken = new EmailVerifyCodeAuthenticationToken(email, redisCode, null);
        log.info("[attemptAuthentication] token:{}", authenticationToken);
        authenticationToken.setDetails(authenticationDetailsSource.buildDetails(request));
        return this.getAuthenticationManager().authenticate(authenticationToken);
    }
}
